package repository

import (
	"errors"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntity"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntityManager"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisService"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"strings"
)

type repoLocalJsnModelService struct {
}

func (e *repoLocalJsnModelService) selectEntityList(body map[string]interface{}) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceModelEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceModelEntity)

		result := true

		if Map.Has(body, "deviceType") {
			result = result && strings.Contains(entity.DeviceType, body["deviceType"].(string))
		}
		if Map.Has(body, "manufacturer") {
			result = result && entity.Manufacturer == body["manufacturer"]
		}
		if Map.Has(body, "modelName") {
			result = result && entity.ModelName == body["modelName"]
		}

		return result
	})
}

func (e *repoLocalJsnModelService) GetDeviceModelEntityList(compEntity *edgeEntity.RepoCompEntity) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceModelEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceModelEntity)

		manufacturer := Map.GetString(compEntity.CompParam, "manufacturer", "")
		deviceType := Map.GetString(compEntity.CompParam, "deviceType", "")

		if entity.Manufacturer != manufacturer {
			return false
		}
		return entity.DeviceType == deviceType
	})
}

func (e *repoLocalJsnModelService) InsertOrUpdate(body map[string]interface{}) error {
	// 提取业务参数
	compId := Map.GetInt64(body, "compId", 0)
	modelName := Map.GetString(body, "modelName", "")
	modelParam := Map.GetMap(body, "modelParam", nil)
	extendParam := Map.GetMap(body, "extendParam", nil)

	// 简单校验参数
	if Method.HasNull(body, "compId", "modelName") {
		return errors.New("参数不能为空: compId, modelName")
	}

	// 验证参数格式
	err := e.verifyModelParam(modelParam)
	if err != nil {
		return err
	}

	exist := commRedisService.GetEntityById(edgeEntity.Type.RepoCompEntity.Type(), compId)
	if exist == nil {
		return errors.New("找不到对应的组件" + String.ToString(compId))
	}
	compEntity := exist.(*edgeEntity.RepoCompEntity)

	manufacturer := Map.GetString(compEntity.CompParam, "manufacturer", "")
	deviceType := Map.GetString(compEntity.CompParam, "deviceType", "")
	if Method.HasEmpty(manufacturer, deviceType) {
		return errors.New("参数不能为空: manufacturer, deviceType")
	}

	// 构造作为参数的实体
	entity := edgeEntity.Type.DeviceModelEntity.Instance()
	entity.ModelName = modelName
	entity.DeviceType = deviceType
	entity.Manufacturer = manufacturer
	entity.ModelParam = modelParam
	entity.ExtendParam = extendParam

	// 新增/修改实体：参数不包含id为新增，包含为修改
	if !Map.Has(body, "id") {
		if entity.ModelParam == nil {
			entity.ModelParam = make(map[string]interface{})
		}
		if entity.ExtendParam == nil {
			entity.ExtendParam = make(map[string]interface{})
		}

		exist, err := commEntityManager.GetEntityByServiceKey(entity.Type(), entity.MakeServiceKey())
		if err != nil {
			return err
		}
		if exist != nil {
			return errors.New("实体已存在")
		}

		err = commEntityManager.InsertEntity(entity)
		if err != nil {
			return err
		}

		return nil
	} else {
		id := Map.GetInt64(body, "id", 0)

		if entity.ModelParam == nil {
			entity.ModelParam = make(map[string]interface{})
		}
		if entity.ExtendParam == nil {
			entity.ExtendParam = make(map[string]interface{})
		}

		exist := commEntityManager.GetEntityById(entity.Type(), id)
		if exist == nil {
			return errors.New("实体不存在")
		}

		if exist.(*edgeEntity.DeviceModelEntity).Manufacturer != manufacturer || exist.(*edgeEntity.DeviceModelEntity).DeviceType != deviceType {
			return errors.New("不允许修改，否则影响关联关系：manufacturer, deviceType, engineType, operateName")
		}

		// 修改数据
		entity.BaseEntity.Id = id
		entity.GetBaseEntity().CreateTime = exist.GetBaseEntity().CreateTime
		entity.GetBaseEntity().UpdateTime = exist.GetBaseEntity().UpdateTime
		return commEntityManager.UpdateEntity(entity)
	}
}

func (e *repoLocalJsnModelService) verifyModelParam(modelParam map[string]interface{}) (err error) {
	// 定义一个最终的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			message := fmt.Sprintf("repoLocalJsnModelService.verifyModelParam() 捕获到异常:%v", r)
			err = errors.New(message)
		}
	}()

	// 参数检测：通过强制转换，检测是否会发生panic，然后被上面的defer捕获
	Map.GetSlice(modelParam, "list", nil)
	Map.GetMap(modelParam, "engine", nil)
	Map.GetString(modelParam, "manufacturer", "")
	Map.GetString(modelParam, "deviceType", "")

	return nil
}

func (e *repoLocalJsnModelService) DeleteEntity(id int64) {
	entity := commEntityManager.GetEntityById(edgeEntity.Type.DeviceModelEntity.Type(), id)
	if entity == nil {
		return
	}

	err := commEntityManager.DeleteEntity(entity)
	if err != nil {
		return
	}
}

func (e *repoLocalJsnModelService) QueryEntity(id int64) *edgeEntity.DeviceModelEntity {
	exist := commEntityManager.GetEntityById(edgeEntity.Type.DeviceModelEntity.Type(), id)
	if exist == nil {
		return nil
	}

	return exist.(*edgeEntity.DeviceModelEntity)
}

func (e *repoLocalJsnModelService) getCompEntity(manufacturer, deviceType string) *edgeEntity.RepoCompEntity {
	exist := commEntityManager.FindEntity(edgeEntity.Type.RepoCompEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.RepoCompEntity)

		if "jsn-decoder" != entity.CompType {
			return false
		}
		if manufacturer != Map.GetString(entity.CompParam, "manufacturer", "") {
			return false
		}
		if deviceType != Map.GetString(entity.CompParam, "deviceType", "") {
			return false
		}

		return true
	})

	if exist == nil {
		return nil
	}

	return exist.(*edgeEntity.RepoCompEntity)
}

func (e *repoLocalJsnModelService) getDeviceModelEntityList(manufacturer, deviceType string) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceModelEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceModelEntity)

		if manufacturer != entity.Manufacturer {
			return false
		}
		if deviceType != entity.DeviceType {
			return false
		}

		return true
	})
}
